package com.naiterui.common.repository.core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.common.repository.exception.DataAccessOpException;
import com.naiterui.common.repository.exception.DataAccessSafeException;

/**
 * 基于SimpleJpaRepository，用于扩展spring-data-jpa相关Repository接口的默认实现，
 * 在配置repository时要将改类作为base-class进行制定，
 * 该类同时也是BaseJpaRepository的实现，扩展的相关行为参见父接口
 *
 * @author zhouyanxin
 * @since 1.0.0
 */
public final class BaseJpaRespositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseJpaRepository<T, ID> {

    /**
     * Entity Manager
     */
    private final EntityManager entityManager;
    private final JpaEntityInformation<T, ID> entityInformation;

    /**
     * 构造函数
     */
    public BaseJpaRespositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
        this.entityInformation = entityInformation;
    }

    /**
     * 根据ID获取实体
     *
     * @param id
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see BaseJpaRepository#get(java.io.Serializable)
     * @since 1.0.0
     */
    @Override
    public T get(ID id) {
        Optional<T> option = this.findById(id);
        return option.orElse(null);
    }

    /**
     * 持久化实体
     *
     * @param s
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see BaseJpaRepository#get(java.io.Serializable)
     * @since 1.0.0
     */
    @Override
    @Transactional
    public <S extends T> S save(S s) {
        if (!this.entityInformation.isNew(s)) {
            throw new DataAccessOpException("persistent object detected !");
        }
        this.entityManager.persist(s);
        return s;
    }

    /**
     * 非持久化对象，执行save操作
     * 已持久化对象，执行update操作
     *
     * @param entity
     *
     * @return
     */
    @Override
    public <S extends T> S saveOrUpdate(S s) {
        if (!this.entityInformation.isNew(s)) {
            this.update(s);
        } else {
            this.save(s);
        }
        return s;
    }

    /**
     * 批量保存实体对象
     * 其行为的变化在于不处理对象的更新
     *
     * @param entities
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年11月18日
     * @since 1.0.0
     */
    @Override
    @Transactional
    public <S extends T> List<S> save(Iterable<S> entities) {
        return this.saveOrUpdate(entities);
    }

    /**
     * 更新实体
     *
     * @param s
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see BaseJpaRepository#get(java.io.Serializable)
     * @since 1.0.0
     */
    @Override
    @Transactional
    public <S extends T> S update(S s) {
        if (this.entityInformation.isNew(s)) {
            throw new DataAccessOpException("persistent non object detected !");
        }
        return this.entityManager.merge(s);
    }

    /**
     * 批量更新实体对象
     * BaseJpaRepository.update()
     *
     * @param entities
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年11月18日
     * @since 1.0.0
     */
    @Transactional
    @Override
    public <S extends T> List<S> update(Iterable<S> entities) {
        return this.saveOrUpdate(entities);
    }

    /**
     * 删除对象
     *
     * @param s
     *
     * @Author zhouyanxin
     * @Date 2018年5月2日
     * @see BaseOperations#remove(java.lang.Object)
     * @since 1.0.0
     */
    @Override
    @Transactional
    public <S extends T> void remove(S s) {
        super.delete(s);
    }

    /**
     * 批量删除
     *
     * @param entities
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @since 1.0.0
     */
    @Override
    @Transactional
    public void remove(List<T> entities) {
        super.deleteInBatch(entities);
    }

    /**
     * 根据ID删除对象
     *
     * @param id
     *
     * @Author zhouyanxin
     * @Date 2018年5月2日
     * @since 1.0.0
     */
    @Override
    @Transactional
    public void removeById(ID id) {
        super.deleteById(id);
    }

    /**
     * 禁用该方法
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see BaseJpaRepository#get(java.io.Serializable)
     * @since 1.0.0
     */
    @Override
    @Transactional
    public void deleteAll() {
        throw new DataAccessSafeException("not support operation, This operation is risky !");
    }

    /**
     * 禁用该方法
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年8月21日
     * @see BaseJpaRepository#get(java.io.Serializable)
     * @since 1.0.0
     */
    @Override
    @Transactional
    public void deleteAllInBatch() {
        throw new DataAccessSafeException("not support operation, This operation is risky !");
    }

    /**
     * 批量保存或更新操作
     *
     * @param entities
     *
     * @return
     *
     * @Author zhouyanxin
     * @Date 2017年11月18日
     * @since 1.0.0
     */
    private <S extends T> List<S> saveOrUpdate(Iterable<S> entities) {

        List<S> result = new ArrayList<S>();

        if (entities == null) {
            return result;
        }

        for (S entity : entities) {
            if (this.entityInformation.isNew(entity)) {
                result.add(this.save(entity));
            } else {
                result.add(this.update(entity));
            }
        }

        return result;

    }
}
